#ifndef NODE_HXX
#define NODE_HXX

#include "rutil/Data.hxx"
#include "Symbols.h"
#include <vector>

namespace codegen
{
    typedef uint32_t Depth;

    class IndentSetting
    {
    public:
        static IndentSetting& instance() {
            static IndentSetting instance_;
            return instance_;
        }
        static const bool& enable() { return instance().enable_; }
        static const bool& reserve_tab() { return instance().reserve_tab_; }
        static const unsigned int& space_count() { return instance().space_count_; }

        void setting(bool enableIndent = true, bool reserveTab = false, unsigned int spaceCount = 4)
        {
            enable_ = enableIndent;
            reserve_tab_ = reserveTab;
            space_count_ = spaceCount;
        }
    private:
        IndentSetting(bool enableIndent = true, bool reserveTab = false, unsigned int spaceCount = 4)
            : enable_(enableIndent), reserve_tab_(reserveTab), space_count_(spaceCount) {}
        bool            enable_;
        bool            reserve_tab_;
        unsigned int    space_count_;
    };

    class LeadingIndent
    {
    public:
        LeadingIndent(Depth depth) : depth_(depth) {}
        friend EncodeStream& operator<<(EncodeStream& ostm, const LeadingIndent& rhs) {
            if (IndentSetting::enable())
            {
                if (IndentSetting::reserve_tab())
                    return ostm << std::string(rhs.depth_, Symbols::TAB[0]);
                else
                {
                    return ostm << std::string(rhs.depth_ * IndentSetting::space_count(), Symbols::SPACE[0]);
                }
            }
            return ostm;
        }
    private:
        Depth depth_;
    };

    class Generator;
    class Node
    {
    public:
        typedef enum Type {
            VT_Int,
            VT_UInt,
            VT_Int64,
            VT_UInt64,
            VT_Float,
            VT_Double,
            VT_Bool,
            VT_String,
            VT_Array,
            VT_Object,
        }Type;

        Node(Type type,
            const resip::Data& key,
            const resip::Data& val,
            const Node* parent,
            Generator* gen)
            : type_(type)
            , depth_(parent ? (parent->isArray() ? parent->depth_ : parent->depth_ + 1) : 0)
            , key_(key)
            , val_(val)
            , parent_(parent)
            , generator_(gen)
        {
        }
        virtual ~Node();

        bool isObject() const { return VT_Object == type_; }
        bool isArray() const { return VT_Array == type_; }
        bool isCompound() const { return isObject() || isArray(); }
        bool isRoot() const { return !parent_; }

        void add_child(const Node* child)
        {
            childs_.push_back(child);
        }

        virtual resip::Data str_type(bool use_alias = false) const;
        virtual resip::Data str_name() const;
        resip::Data str_arr_size_name() const;
        resip::Data str_arr_size_index_name() const;
        resip::Data str_com_tmp_name() const;
        resip::Data str_parent_class_name() const;

        virtual EncodeStream& encode(EncodeStream& ostm) const;
        virtual EncodeStream& encode_class_begin(EncodeStream& ostm) const;
        virtual EncodeStream& encode_class_end(EncodeStream& ostm) const;
        virtual EncodeStream& encode_class_ctor_dector(EncodeStream& ostm) const;
        virtual EncodeStream& encode_class_ctor(EncodeStream& ostm) const;
        virtual EncodeStream& encode_class_dector(EncodeStream& ostm) const;
        virtual EncodeStream& encode_member_init(EncodeStream& ostm) const;
        virtual EncodeStream& encode_member_uninit(EncodeStream& ostm) const;
        virtual EncodeStream& encode_member_get_set_function(EncodeStream& ostm) const;
        virtual EncodeStream& encode_custom_function(EncodeStream& ostm) const;
        virtual EncodeStream& encode_member_declaration(EncodeStream& ostm) const;

        Type        type_;
        Depth       depth_;
        resip::Data key_;
        resip::Data val_;
        std::vector<const Node*>    childs_;
        const Node*                 parent_;
        Generator* generator_;
    };
    typedef std::vector<const Node*> NodeContainer;

}


#endif // #ifndef NODE_HXX
